﻿using System;
using System.Linq;
using Prism.Events;
using FrameWork.Core.Enum;
using FrameWork.Core.China;
using FrameWork.Core.Event;
using FrameWork.Core.Collection;
using System.Collections.Generic;
using FrameWork.Core.Chain.Entitys;
using FrameWork.Core.Chain.Invengo;
using FrameWork.Core.Infrastructure;

namespace FrameWork.WorkFlow.Channel
{
    public class NodeEngine<P, R> : InvengoChainEngine<P>, IChainEngine<P>
        where P : InvengoProcess<R>, new()
        where R : ProcessDataBase, new()
    {
        #region ___构造函数___
        /// <summary>
        /// 构造函数
        /// </summary>
        public NodeEngine()
        { }
        #endregion

        #region ___类内方法___
        /// <summary>
        /// 节点过滤器
        /// </summary>
        /// <param name="process"></param>
        /// <returns></returns>
        protected Func<ProcessBase, IEnumerable<IProcessNode>> GetDefaultNodeFilter(P process)
        {
            return process.ProcessNodeFilter ?? DefaultNodeFilter;
        }
        /// <summary>
        /// 默认根据FlowType获取节点
        /// </summary>
        /// <param name="ChannelType"></param>
        /// <returns></returns>
        private IEnumerable<IProcessNode> DefaultNodeFilter(ProcessBase process)
        {
            return EngineContext.Current.ResolveAll<IProcessNode>()
                 .Where(t => t.SupportFlowTypes.Contains(process.FlowType))
                 .ToList();
        }
        /// <summary>
        /// 执行规则
        /// </summary>
        /// <param name="record"></param>
        public override void Process(P processBase)
        {
            try
            {
                if (HasRegister(processBase))
                    return;
                //////////////设置流程过滤器/////////////////////
                var checkPointFilter = GetDefaultNodeFilter(processBase);
                InvengoLink<IProcessNode> m_LinkList = new InvengoLink<IProcessNode>();
                var checkPoints = checkPointFilter(processBase);
                Console.WriteLine(string.Join<string>("->", checkPoints.Select(t => t.GetType().Name)));
                //////////////节点替换(用xxEx节点替换xx节点)///////////
                checkPoints = checkPoints.Where(t => !checkPoints.Where(n => n.GetType().Name.Contains(t.GetType().Name + "Ex")).Any())
                               .OrderBy(t => t.Order)
                               .ToList();
                checkPoints.ToList().ForEach(t => m_LinkList.Append(t, t.Index));
                processBase.TotalNode = checkPoints.Count();
                if (!m_LinkList.IsEmpty())
                {
                    Console.WriteLine("---------------流程开始--------------");
                    ///////////取第一个节点或者续接节点//////
                    var m_NextNode = processBase.Record.StartOrder == 0 ? m_LinkList.Head : m_LinkList.GetNodeByValue(processBase.Record.StartOrder);
                    if ((bool)!processBase.Prepare?.Invoke(processBase.Record))
                    {
                        var message = @"流程【" + processBase.FlowName + "】前置条件不通过，流程终止";
                        //EngineContext.Current.Resolve<IEventAggregator>().GetEvent<SystemEvent>().Publish(new Core.Base.SystemNotify()
                        //{
                        //    Title = processBase.Record.ReaderNo,
                        //    Describe = message,
                        //    CreateTime = DateTime.Now,
                        //    AlarmLevel = Core.Enum.EnumAlarmLevel.Danger,
                        //});
                        processBase.Record.Message = message;
                        processBase.State = EnumProcessState.Break;
                        processBase.ClearUp?.Invoke(processBase.Record);
                        return;
                    }
                    while (null != m_NextNode)
                    {
                        //////////流程中止////////
                        if ((processBase.Cts != null && processBase.Cts.IsCancellationRequested)
                             || processBase.State == EnumProcessState.Break)
                        {
                            processBase.ClearUp?.Invoke(processBase.Record);
                            Console.WriteLine("流程【" + processBase.FlowName + "】被停止");
                            break;
                        }
                        processBase.Record.Index++;
                        processBase.Record.CurrentNode = m_NextNode.Data;
                        m_NextNode.Data.Prepare(processBase, processBase.Record);
                        Console.WriteLine("开始执行节点【" + processBase.FlowName + "->" + m_NextNode.Data.Index + "->" + m_NextNode.Data.GetType().Name + "】");
                        m_NextNode.Data.Process(processBase, processBase.Record);
                        Console.WriteLine("执行节点【" + processBase.FlowName + "->" + m_NextNode.Data.Index + "->" + m_NextNode.Data.GetType().Name + "】" + (processBase.State == EnumProcessState.Finish ? "成功" : "失败"));
                        m_NextNode.Data.ClearUp(processBase, processBase.Record);
                        //processBase.Record.Track.ToList().Add(new TrackNode() { Success = processBase.Success, NodeId = m_NextNode.Data.Order, NodeName = m_NextNode.Data.NodeName, NodeType = m_NextNode.Data.NodeType });
                        //////////////////////跳转节点不为空先跳转//////////////////////////
                        if (m_NextNode.Data.NextOrder > 0)
                        {
                            var nextNode = m_LinkList.GetNodeByValue(m_NextNode.Data.NextOrder);
                            m_NextNode = (null != nextNode) ? nextNode : null;
                        }
                        else
                        {
                            m_NextNode = null != m_NextNode.Next ? m_NextNode.Next : null;
                        }
                        if (null == m_NextNode)
                        {
                            processBase.ClearUp?.Invoke(processBase.Record);
                            break;
                        }
                    }
                    Console.WriteLine("---------------流程结束--------------");
                }
                else
                    Console.WriteLine("链表为空");
            }
            catch (Exception ex)
            {
                processBase.ClearUp?.Invoke(processBase.Record);
                EngineContext.Current.Resolve<IEventAggregator>().GetEvent<SystemEvent>().Publish(new Core.Base.SystemNotify()
                {
                    Title = processBase.Record.ReaderNo,
                    Describe = "流程发生错误:" + ex.Message,
                    CreateTime = DateTime.Now,
                    AlarmLevel = 0,
                });
                Console.WriteLine("【" + processBase.FlowName + "】流程执行发生错误,", ex.Message);
            }
            finally
            {
                UnRegister(processBase);
            }
        }
        #endregion
    }
}